﻿namespace Bowlus.Common
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;

    public class TenantDeploymentsStore : TableServiceContext
    {
        private static readonly object LockObject = new object();

        private const string TenantDeploymentTableName = "TenantDeployment";

        private static volatile bool InitializedTable;

        private TenantDeploymentsStore(CloudStorageAccount account)
            : base(account.TableEndpoint.AbsoluteUri, account.Credentials)
        {
            var tableClient = new CloudTableClient(account.TableEndpoint.AbsoluteUri, account.Credentials);

            //if (
            tableClient.CreateTableIfNotExist(TenantDeploymentTableName);
            //{
            //    return;
            //}

            //var tenantDeployment = new TenantDeployment
            //    {
            //        RowKey = "initalizer",
            //        Application = "initalizer",
            //        Customizations = "initalizer",
            //        HostName = "initalizer",
            //        AppHostInstanceId = "initalizer",
            //        AppHostInstanceIp = "initalizer",
            //        Status = "initalizer",
            //        TenantId = "initalizer"
            //    };
            //this.Deploy(tenantDeployment);
            //this.SaveChanges();
        }

        public static TenantDeploymentsStore Instance
        {
            get
            {
                var instance = new TenantDeploymentsStore(Settings.AzureStorageAccount);
                // HACK: HACK HACK HACK HACK HACK HACK 
                if (!InitializedTable)
                {
                    lock (LockObject)
                    {
                        if (
                            Settings.AzureStorageAccount.CreateCloudTableClient().BaseUri.AbsoluteUri.Contains(
                                "devstoreaccount"))
                        {
                            // HACK: for local store because of the lack of feature parity between local and cloud :(
                            try
                            {
                                var query = instance.TenantDeployment.ToList();
                            }
                            catch (Exception exception)
                            {
                                var dummyRecord = new TenantDeployment();
                                instance.AddObject(TenantDeploymentTableName, dummyRecord);
                                instance.SaveChanges();
                                instance.DeleteObject(dummyRecord);
                                instance.SaveChanges();

                                BowlusLogger.LogError(exception.ToString());
                            }
                        }

                        InitializedTable = true;
                    }
                }

                return instance;
            }
        }

        public IQueryable<TenantDeployment> TenantDeployment
        {
            get
            {
                return CreateQuery<TenantDeployment>(TenantDeploymentTableName).Where(c => c.PartitionKey == "_bowlus").AsTableServiceQuery();
            }
        }

        public static IEnumerable<TenantDeployment> GetCurrentDeployments()
        {
            // TODO: Organize deployment states
            var deployments = from tenantDeployment in Instance.TenantDeployment
                              select tenantDeployment;

            return deployments;
        }

        public static void UpdateDeploymentStore(IEnumerable<TenantDeployment> tenantDeployments)
        {
            foreach (var td in tenantDeployments)
            {
                UpdateDeploymentStore(td);
            }
        }

        public static void UpdateDeploymentStore(TenantDeployment tenantDeployment)
        {
            BowlusLogger.LogInfo(string.Format("UPDATING STORE: {0}", string.Join(",", tenantDeployment.Serialize())));

        	var clone = tenantDeployment.Clone();
            var tableContext = Instance;
            var tenantDeployments = tableContext.TenantDeployment.ToList();

            // update tenant table
            if (tenantDeployments.Any(td => td.HostName.Equals(tenantDeployment.HostName)))
            {
                var entity = tenantDeployments.Find(td => td.HostName.Equals(tenantDeployment.HostName));
                if (entity != null)
                {
                    entity.DeepCopy(clone);
                    tableContext.Update(entity);
                }
            }
            else
            {
                tableContext.Add(tenantDeployment);
            }
        }

        private void Add(TenantDeployment tenantDeployment)
        {
            this.AddObject(TenantDeploymentTableName, tenantDeployment);
            this.SaveChanges();
        }

        private void Update(TenantDeployment deployment)
        {
            this.UpdateObject(deployment);
            this.SaveChanges();
        }
    }
}
